// com/dz/aspect/OperationLogAspect.java
package com.dz.aspect;

import com.dz.annotation.OperationLog;
import com.dz.bean.GuideLog;
import com.dz.bean.ManagerLog;
import com.dz.bean.VisitorLog;
import com.dz.service.LogService;
import com.dz.util.SYS;
import com.dz.util.TokenUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Slf4j
@Aspect
@Component
public class OperationLogAspect {

    @Autowired
    private LogService logService;

    // 定义切点 - 拦截带有 @OperationLog 注解的方法
    @Pointcut("@annotation(com.dz.annotation.OperationLog)")
    public void operationLogPointCut() {}

    // 环绕通知
    @Around("operationLogPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // 执行方法
        Object result = point.proceed();
        // 执行时长(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        // 保存日志
        saveOperationLog(point, time);
        return result;
    }

    private void saveOperationLog(ProceedingJoinPoint joinPoint, long time) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        OperationLog operationLogAnnotation = method.getAnnotation(OperationLog.class);
        if (operationLogAnnotation == null) {
            return;
        }

        // 获取当前请求
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }

        HttpServletRequest request = attributes.getRequest();

        // 获取token信息
        String token = request.getHeader(SYS.TOKEN_AUTHORIZATION);
        if (token == null || !TokenUtil.verify(token)) {
            return;
        }

        String role = TokenUtil.getRole(token);
        Integer userId = TokenUtil.getId(token);

        if (userId == null) {
            return;
        }

        // 获取注解上的描述
        String operation = operationLogAnnotation.value();

        // 请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        String methodStr = className + "." + methodName + "()";

        // 请求的参数
        Object[] args = joinPoint.getArgs();
        String params = "";
        try {
            if (args != null && args.length > 0 && args[0] != null) {
                params = com.alibaba.fastjson.JSON.toJSONString(args[0]);
            }
        } catch (Exception e) {
            params = "参数序列化失败";
        }

        // 根据角色保存日志
        try {
            switch (role) {
                case SYS.ROLE_MANAGER:
                    ManagerLog managerLog = new ManagerLog();
                    managerLog.setManagerId(userId);
                    managerLog.setOperateTime(LocalDateTime.now());
                    managerLog.setMethodName(methodStr);
                    managerLog.setMethodParams(params);
                    managerLog.setResult(operation);
                    managerLog.setCostTime(time);
                    logService.saveManagerLog(managerLog);
                    break;

                case SYS.ROLE_GUIDE:
                    GuideLog guideLog = new GuideLog();
                    guideLog.setGuideId(userId);
                    guideLog.setOperateTime(LocalDateTime.now());
                    guideLog.setMethodName(methodStr);
                    guideLog.setMethodParams(params);
                    guideLog.setResult(operation);
                    guideLog.setCostTime(time);
                    logService.saveGuideLog(guideLog);
                    break;

                case SYS.ROLE_VISITOR:
                    VisitorLog visitorLog = new VisitorLog();
                    visitorLog.setVisitorId(userId);
                    visitorLog.setOperateTime(LocalDateTime.now());
                    visitorLog.setMethodName(methodStr);
                    visitorLog.setMethodParams(params);
                    visitorLog.setResult(operation);
                    visitorLog.setCostTime(time);
                    logService.saveVisitorLog(visitorLog);
                    break;
            }
        } catch (Exception e) {
            log.error("保存操作日志失败", e);
        }
    }
}
